#ifndef _SPARSE_NODE_H_
#define _SPARSE_NODE_H_

#include <Windows.h>

#include <list>
#include <algorithm>

#include "utils.h"
#include "xml_parse.h"

class sparse_node {
protected:
	u64 start_pos;
	u64 data_length;
	u64 space_after;
	u64 block;
public:
	sparse_node(u64 s, u64 l, u64 b, u64 sa) {
		start_pos = s;
		data_length = l;
		block = b;
		space_after = sa;
	}
	void set_length(u64 l) {
		data_length = l;
	}
	void set_space(u64 space) {
		space_after = space;
	}
	void print_node() {
		printf("start: %llu, length: %llu, block: %llu, space: %llu\n", start_pos, data_length, block, space_after);
	}

	int write_file(HANDLE h_in_file, char *out_file_name);
	virtual const char* get_file_fmt() = 0;
	virtual void update_xml_node(xml_node *node, const char *file_name, const char *label, DWORD base_sector) = 0;
};

class sparse_node_v1: virtual public sparse_node {
protected:
	sparse_node_v1(u64 s, u64 l, u64 b, u64 sa):sparse_node(s, l, b, sa) {}
	friend class sparse_node_factory;
public:
	static const char* static_get_file_fmt() { return "%s_%d.unsparse"; }
	const char* get_file_fmt() { return static_get_file_fmt(); }
	void update_xml_node(xml_node *node, const char *file_name, const char *label, DWORD base_sector);
};

class sparse_node_v2: virtual public sparse_node {
protected:
	sparse_node_v2(u64 s, u64 l, u64 b, u64 sa):sparse_node(s, l, b, sa) {}
	friend class sparse_node_factory;
public:
	static const char* static_get_file_fmt() { return "%s_%d.img"; }
	const char* get_file_fmt() { return static_get_file_fmt(); }
	void update_xml_node(xml_node *node, const char *file_name, const char *label, DWORD base_sector);
};

class sparse_node_v3: virtual public sparse_node {
protected:
	sparse_node_v3(u64 s, u64 l, u64 b, u64 sa):sparse_node(s, l, b, sa) {}
	friend class sparse_node_factory;
public:
	static const char* static_get_file_fmt() { return "%s_%d.img"; }
	const char* get_file_fmt() { return static_get_file_fmt(); }
	void update_xml_node(xml_node *node, const char *file_name, const char *label, DWORD base_sector);
};

enum SPARSE_NODE_VERSIONS {
	UNKNOWN,
	V1,
	V2,
	V3
};

class sparse_node_factory {
private:
	sparse_node_factory() { version = UNKNOWN; }
	sparse_node_factory(sparse_node_factory const&);
    void operator=(sparse_node_factory const&);
	SPARSE_NODE_VERSIONS version;
public:
	static sparse_node_factory& get_instance();
	int init(xml_node *part_node);
	SPARSE_NODE_VERSIONS get_version() { return version; }
	sparse_node* new_sparse_node(u64 s, u64 l, u64 b, u64 sa);
	bool is_first_node(const char *filename, const char *label);
};

#endif